﻿using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using Newtonsoft.Json;
using TMPro;
using UnityEngine;
using Yoozoo.Mars.Got;

namespace Yoozoo.Gameplay.City
{
    public class CityFogAreaEditor : AreaEditorBase
    {
#if UNITY_EDITOR
        [Header("是否自动显示标签")]
        public bool AutoBuildLabelEnable;
        
        private List<GameObject> hudList = new List<GameObject>();

        private float rebuildLabelInterval = 1;

        private float rebuildLabelTimer = 0;
        

       

        protected override void OnEditing()
        {
            if (Input.GetKey(KeyCode.LeftShift))
            {
                // 按住Shift，点中心自动填充
                if (Input.GetMouseButton(1))
                {
                    Vector3 hitPos;
                    if (GetClickPos(Input.mousePosition, out hitPos))
                    {
                        Vector2Int grid = GetGrid(hitPos);
                        AutoFill(grid);
                    }
                }
            }
            else
            {
                base.OnEditing();
            }

            if(AutoBuildLabelEnable)
                AutoRebuildLabel();
        }

        #region 添加雾区域的标签

        private void AutoRebuildLabel()
        {
            rebuildLabelTimer += Time.deltaTime;
            if (rebuildLabelTimer < rebuildLabelInterval)
                return;

            rebuildLabelTimer = 0;
            BuildLabel();
        }

        public void DestroyLabel()
        {
            foreach (var hud in hudList)
            {
                Destroy(hud);
            }
            hudList.Clear();
        }

        public void BuildLabel()
        {
            DestroyLabel();

            // 相同areaId的格子可能并不相互联通，需要分别进行标记
            var visitedArea = new int[width, height];

            for (int i = 0; i < width; i++)
            {
                for (int j = 0; j < height; j++)
                {
                    if(visitedArea[i, j] != 0)
                        continue;

                    visitedArea[i, j] = 1;
                    if (areaIdArray[i, j] == 0)
                        continue;

                    // 找到一个区域，寻找联通的所有格子
                    int areaId = areaIdArray[i, j];
                    var openList = new List<Vector2Int> {new Vector2Int(i, j)};
                    var group = FindGridGroup(areaId, openList);
                    float totalX = 0;
                    float totalY = 0;
                    int maxX = 0;
                    int minX = int.MaxValue;
                    foreach (var grid in group)
                    {
                        visitedArea[grid.x, grid.y] = 1;

                        if (grid.x < minX)
                            minX = grid.x;
                        if (grid.x > maxX)
                            maxX = grid.x;

                        var pos = GetPos(grid);
                        totalX += pos.x;
                        totalY += pos.z;
                    }

                    float posX = totalX / group.Count;
                    float posY = totalY / group.Count;
                    float scale = 0.08f * (maxX - minX + 1);
                    if (scale > 1)
                        scale = 1;
                    
                    var hud = CreateHud(areaId, new Vector3(posX, 0.1f, posY), scale);
                    hudList.Add(hud);
                }
            }
        }

        private GameObject CreateHud(int areaId, Vector3 pos, float scale)
        {
            var prefab = UnityEditor.AssetDatabase.LoadAssetAtPath<GameObject>("Assets/Arts/Scene/City/FogAreaMarker.prefab");
            if (!prefab) 
                return null;
                    
            var o = Instantiate(prefab);
            o.transform.localPosition = pos;
            o.transform.localEulerAngles = new Vector3(0, 45, 0);
            o.transform.localScale = new Vector3(scale, scale, scale);

            o.transform.name = areaId.ToString();
            o.transform.parent = transform;

            var text = o.GetComponentInChildren<TMP_Text>();
            if (text)
            {
                text.text = areaId.ToString();
            }

            return o;
        }

        private List<Vector2Int> FindGridGroup(int areaId, List<Vector2Int> openList)
        {
            var closeList = new List<Vector2Int>();
            var visitedGrids = new HashSet<int>();

            while (openList.Count > 0)
            {
                int lastIndex = openList.Count - 1;
                var i = openList[lastIndex];
                openList.RemoveAt(lastIndex);
                var x = i.x;
                var y = i.y;
                if (areaIdArray[x, y] == areaId)
                {
                    // 相同areaId的格子，加入closeList
                    // 周围4个格子加入openList
                    closeList.Add(i);
                    AddToOpenList(new Vector2Int(x + 1, y), visitedGrids, openList);
                    AddToOpenList(new Vector2Int(x - 1, y), visitedGrids, openList);
                    AddToOpenList(new Vector2Int(x, y + 1), visitedGrids, openList);
                    AddToOpenList(new Vector2Int(x, y - 1), visitedGrids, openList);
                }
            }

            return closeList;
        }

        #endregion

        #region 半自动填充闭环内的所有格子

        /// <summary>
        /// 半自动填充闭环内的所有格子
        /// </summary>
        /// <param name="grid"></param>
        private void AutoFill(Vector2Int grid)
        {
            // 策划需求：同id迷雾编辑形成闭环时，自动填充里面所有的空间
            // 自动检查不好搞，改成点中心自动填充
            if (!_areaConfigMap.ContainsKey(currentAreaId))
                return;

            if (grid.x == 0 || grid.x >= width)
                return;

            if (grid.y == 0 || grid.y >= height)
                return;
            
            var openList = new List<Vector2Int>();
            var closeList = new List<Vector2Int>();
            var visitedGrids = new HashSet<int>();
            openList.Add(grid);
            visitedGrids.Add(GetGridId(grid));

            // 是否闭合
            bool isClosed = true;
            while (openList.Count > 0)
            {
                int lastIndex = openList.Count - 1;
                var i = openList[lastIndex];
                openList.RemoveAt(lastIndex);
                var x = i.x;
                var y = i.y;
                if (areaIdArray[x, y] == currentAreaId)
                {
                    // 环形的边界，不再扩展
                }
                else if (x == 0 || x >= width || y == 0 || y >= height)
                {
                    // 地图的边界，碰到这里说明没有包围，失败
                    isClosed = false;
                    break;
                }
                else
                {
                    // 其他格子，不管是空的还是设置过的，都加入closeList
                    // 周围4个格子加入openList
                    closeList.Add(i);
                    AddToOpenList(new Vector2Int(x + 1, y), visitedGrids, openList);
                    AddToOpenList(new Vector2Int(x - 1, y), visitedGrids, openList);
                    AddToOpenList(new Vector2Int(x, y + 1), visitedGrids, openList);
                    AddToOpenList(new Vector2Int(x, y - 1), visitedGrids, openList);
                }
            }

            if (isClosed)
            {
                foreach (var i in closeList)
                {
                    WritePixel(i);
                }
                areaTexture.Apply();
            }
        }

        /// <summary>
        /// 将格子添加到OpenList，并且标记为已访问
        /// </summary>
        /// <param name="grid"></param>
        /// <param name="visitedGrids"></param>
        /// <param name="openList"></param>
        private void AddToOpenList(Vector2Int grid, HashSet<int> visitedGrids, List<Vector2Int> openList)
        {
            if (grid.x < 0 || grid.x >= width)
                return;

            if (grid.y < 0 || grid.y >= height)
                return;

            var gridId = GetGridId(grid);
            if (visitedGrids.Contains(gridId)) 
                return;

            openList.Add(grid);
            visitedGrids.Add(gridId);
        }
        #endregion

        #region 其他操作

        public void DeleteCurrentArea()
        {
            var grid = new Vector2Int();
            for (int i = 0; i < width; i++)
            {
                for (int j = 0; j < height; j++)
                {
                    if(areaIdArray[i, j] == currentAreaId)
                    {
                        grid.x = i;
                        grid.y = j;
                        ClearPixel(grid);
                    }
                }
            }
            areaTexture.Apply();
        }
        
        /// 打印检查矩形结构
        public static void PrintDic(Dictionary<int, List<int[]>> mainDict) 
        {
            StringBuilder sb = new StringBuilder();
            foreach (var pair1 in mainDict.Keys)
            {
                sb.AppendFormat("{0}: [", 
                    pair1);
                foreach (var pair2 in mainDict[pair1])
                {
                    // sb.AppendFormat("{0}", pair2.ToString());
                    sb.AppendFormat("[");
                    foreach (int pair3 in pair2)
                    {
                        sb.AppendFormat("{0}, ", 
                            pair3);
                    }
                    sb.AppendFormat("], ");
                }
                sb.AppendFormat("] ,");
            }

            Debug.Log(sb);
        }

        public static void PrintDicY(Dictionary<string, List<int[]>> mainDict)
        {
            StringBuilder sb = new StringBuilder();
            foreach (var pair1 in mainDict.Keys)
            {
                sb.AppendFormat("{0}: [", 
                    pair1);
                foreach (var pair2 in mainDict[pair1])
                {
                    // sb.AppendFormat("{0}", pair2.ToString());
                    sb.AppendFormat("[");
                    foreach (int pair3 in pair2)
                    {
                        sb.AppendFormat("{0}, ", 
                            pair3);
                    }
                    sb.AppendFormat("], ");
                }
                sb.AppendFormat("] ,");
            }

            Debug.Log(sb);
        }
        
        public static void PrintDicRec(List<int[]> Recs)
        {
            StringBuilder sb = new StringBuilder();
            foreach (var pair1 in Recs)
            {
                sb.AppendFormat("[");

                foreach (var pair2 in pair1)
                {
                    sb.AppendFormat("{0}, ", pair2);

                }
                sb.AppendFormat("] ,");
            }

            Debug.Log(sb);
        }
        
        /// <summary>
        /// 结束编辑时销毁标签
        /// </summary>
        public override void UnShow()
        {
            base.UnShow();
            DestroyLabel();
        }

        // 合并单个区域的所有点坐标为矩形坐标
        public static List<RectInt> MergeOneArea(List<Vector2Int> grids)
        {
            int curX = 0;
            int curYStart = 0;
            int curYEnd = 0;
            
            // 合并 x 
            Dictionary<int, List<int[]>> xDic = new Dictionary<int, List<int[]>>();
            foreach (var grid in grids)
            {
                if (xDic.ContainsKey(grid.x))
                {
                    if (grid.y - xDic[grid.x].Last()[1] == 1)
                    {
                        xDic[grid.x].Last()[1] = grid.y;
                    }
                    else
                    {
                        int[] tmp = {grid.y, grid.y};
                        xDic[grid.x].Add(tmp);
                    }
                }
                else
                {
                    int[] tmp = {grid.y, grid.y};
                    List<int[]> tmpList = new List<int[]>();
                    tmpList.Add(tmp);
                    xDic.Add(grid.x, tmpList);
                }
            }
            // PrintDic(xDic);

            // 合并同一个 x 方向上的 y 坐标
            Dictionary<string, List<int[]>> yDic = new Dictionary<string, List<int[]>>();
            foreach (var xDicX in xDic.Keys)
            {
                foreach (var xDicXArray in xDic[xDicX])
                {
                    string heightRange = $"{xDicXArray[0]},{xDicXArray[1]}";
                    if (yDic.ContainsKey(heightRange))
                    {
                        if (xDicX - yDic[heightRange].Last()[1] == 1)
                        {
                            yDic[heightRange].Last()[1] = xDicX;
                        }
                        else
                        {
                            int[] tmp = {xDicX, xDicX};
                            yDic[heightRange].Add(tmp);
                        }
                    }
                    else
                    {
                        int[] xRange = {xDicX, xDicX};
                        List<int[]> tmpList = new List<int[]>();
                        tmpList.Add(xRange);
                        yDic.Add(heightRange, tmpList);
                    }
                }
            }
            List<RectInt> Recs = new List<RectInt>();
            foreach (string yRange in yDic.Keys)
            {
                List<string> yRangeList = new List<string>(yRange.Split(','));
                int y1 = int.Parse(yRangeList[0]);
                int y2 = int.Parse(yRangeList[1]);
                foreach (var xList in yDic[yRange])
                {
                    
                    int x1 = xList[0];
                    int x2 = xList[1];
                    RectInt rec = new RectInt(x1, y1, x2 - x1, y2 - y1);
                    Recs.Add(rec);
                }
            }
            // PrintDicRec(Recs);
            return Recs;
        }

        public void SaveRec(Dictionary<int, CitySubAreaEditor> citySubAreaMap)
        {
            if (!editing) return;
            
            var areaConfigRec = new CityAreaEditorConfigRec
            {
                width = width,
                height = height,
                citySubAreas = new List<CitySubAreaEditorRec>()
            };
            
            var citySubAreaMapRec = new Dictionary<int, CitySubAreaEditorRec>();
            
            foreach (var citySubAreaMapIndex in citySubAreaMap.Keys)
            {
                var grids = citySubAreaMap[citySubAreaMapIndex].grids;
                if (!citySubAreaMapRec.ContainsKey(citySubAreaMapIndex))
                {
                    // 初始化key
                    CitySubAreaEditorRec citySubAreaEditorRecValue = new CitySubAreaEditorRec();
                    citySubAreaEditorRecValue.areaId = citySubAreaMapIndex;
                    citySubAreaEditorRecValue.grids = new List<RectInt>();
                    citySubAreaMapRec[citySubAreaMapIndex] = citySubAreaEditorRecValue;
                }
                var grs = MergeOneArea(grids);
                citySubAreaMapRec[citySubAreaMapIndex].grids = grs;
            }

            // 以矩形方式保存
            areaConfigRec.citySubAreas.AddRange(citySubAreaMapRec.Values);
            // 以矩形方式保存配置
            var jsonTextRec = JsonUtility.ToJson(areaConfigRec, false);
            var luaText = JsonToLua.ConvertLua(jsonTextRec); 
            string editorRecLuaPath = $"{Application.dataPath}/../Lua/modules/city/config/fogAreaJsonConfigRec.lua";
            FileStream luafs = new FileStream(editorRecLuaPath, FileMode.Create, FileAccess.Write);
            using (StreamWriter writer = new StreamWriter(luafs))
            {
                writer.Write(luaText);
                writer.Flush();
                writer.Close();
                luafs.Close();
            }
            Debug.Log("导出结束！");
            UnityEditor.AssetDatabase.Refresh();
        }
            
        
        public override void Save()
        {
            if (!editing) return;

            // 保存编辑器配置
            var areaConfig = new CityAreaEditorConfig
            {
                width = width,
                height = height,
                citySubAreas = new List<CitySubAreaEditor>()
            };

            var citySubAreaMap = new Dictionary<int, CitySubAreaEditor>();

            for (int i = 0; i < areaIdArray.GetLength(0); i++)
            {
                for (int j = 0; j < areaIdArray.GetLength(1); j++)
                {
                    int areaId = areaIdArray[i, j];
                    if (areaId <= 0)
                    {
                        continue;
                    }

                    if (!citySubAreaMap.ContainsKey(areaId))
                    {
                        var subFog = new CitySubAreaEditor();
                        subFog.areaId = areaId;
                        subFog.grids = new List<Vector2Int>();
                        citySubAreaMap[areaId] = subFog;
                    }

                    citySubAreaMap[areaId].grids.Add(new Vector2Int(i, j));
                }
            }

            areaConfig.citySubAreas.AddRange(citySubAreaMap.Values);

            var jsonText = JsonUtility.ToJson(areaConfig, false);
            FileStream fs = new FileStream(editorConfigPath, FileMode.Create, FileAccess.Write);
            using (StreamWriter writer = new StreamWriter(fs))
            {
                writer.Write(jsonText);
                writer.Flush();
                writer.Close();
                fs.Close();
            }
            UnityEditor.AssetDatabase.Refresh();

            // 保存服务器配置
            FileStream fs2 = new FileStream(serverConfigPath, FileMode.Create, FileAccess.Write);
            using (StreamWriter writer = new StreamWriter(fs2))
            {
                writer.Write(jsonText);
                writer.Flush();
                writer.Close();
                fs2.Close();
            }
            UnityEditor.AssetDatabase.Refresh();
            
            // 存储为矩形结构
            SaveRec(citySubAreaMap);
        }

        #endregion

#endif
    }
}
